home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / archiver / ziptv21.zip / INTRCOMM.INC < prev    next >
Text File  |  1990-04-22  |  15KB  |  597 lines

  1.  
  2. (*
  3.  * Copyright 1987, 1989 Samuel H. Smith;  All rights reserved
  4.  *
  5.  * This is a component of the ProDoor System.
  6.  * Do not distribute modified versions without my permission.
  7.  * Do not remove or alter this notice or any other copyright notice.
  8.  * If you use this in your own program you must distribute source code.
  9.  * Do not use any of this in a commercial product.
  10.  *
  11.  *)
  12.  
  13. (*
  14.  * intrcomm.inc - interrupt-based communication library for PCB ProDOOR
  15.  *
  16.  *)
  17.  
  18. {$R-,S-}
  19.  
  20.  
  21. (* ------------------------------------------------------------ *)
  22. procedure control_k;
  23.    (* process cancel-output command *)
  24. begin
  25.    txque.next_in := 1;
  26.    txque.next_out := 1;          (* throw away pending output *)
  27.    txque.count := 0;             
  28.  
  29.    rxque.next_in := 1;
  30.    rxque.next_out := 1;          (* throw away pending input *)
  31.    rxque.count := 0;
  32.  
  33.    linenum := 9000;              (* cancel current function *)
  34.    pending_keys[0] := #0;
  35. end;
  36.  
  37.  
  38. (* ------------------------------------------------------------ *)
  39. procedure INTR_service_MSR;
  40.   (* modem status change interrupt *)
  41. var
  42.    c: byte;
  43. begin
  44.    c := port[ port_base+MSR ];
  45.    io_delay;
  46. end;
  47.  
  48.  
  49. (* ------------------------------------------------------------ *)
  50. procedure INTR_service_LSR;
  51.    (* line status change interrupt *)
  52. var
  53.    c: byte;
  54. begin
  55.    c := port[ port_base+LSR ];
  56.    io_delay;
  57. end;
  58.  
  59.  
  60. (* ------------------------------------------------------------ *)
  61. procedure INTR_service_transmit;
  62.    (* low-level interrupt service for transmit, call only when transmit
  63.       holding register is empty *)
  64. var
  65.    c:       char;
  66. const
  67.    recur:  boolean = false;
  68.  
  69. begin
  70.  
  71. (* prevent recursion fb/bg *)
  72.    if recur then exit;
  73.    recur := true;
  74.  
  75. (* drop out if transmitter is busy *)
  76.    if (port[ port_base+LSR ] and LSR_THRE) = 0 then
  77.    begin
  78.       io_delay;
  79.       recur := false;
  80.       exit;
  81.    end;
  82.  
  83.    io_delay;
  84.  
  85.    (* stop transmitting when queue is empty, or XOFF is active
  86.       or it is not CLEAR-to-send to modem *)
  87.  
  88.    xmit_active := (txque.count <> 0) and (not xoff_active) and
  89.                   (disable_CTS_check or ((port[port_base+MSR] and MSR_CTS)>0));
  90.  
  91.    io_delay;
  92.  
  93.    (* start next byte transmitting *)
  94.    if xmit_active then
  95.    begin
  96.       c := txque.data[txque.next_out];
  97.       if txque.next_out < sizeof(txque.data) then
  98.          inc(txque.next_out)
  99.       else
  100.          txque.next_out := 1;
  101.       dec(txque.count);
  102.  
  103.       port[ port_base+THR ] := ord(c); io_delay;
  104.    end;
  105.  
  106.    recur := false;
  107. end;
  108.  
  109.  
  110. (* ------------------------------------------------------------ *)
  111. procedure INTR_service_receive;
  112.    (* low-level interrupt service for receive data,
  113.       call only when receive data is ready *)
  114. var
  115.    c: char;
  116.    o: byte;
  117.    err: boolean;
  118.  
  119. begin
  120.    o := port[ port_base+LSR ];
  121.    io_delay;
  122.  
  123.    err := false;
  124.    if (o and LSR_OERR) <> 0 then begin inc(LOERR_count);  err := true; end;
  125.    if (o and LSR_PERR) <> 0 then begin inc(LPERR_count);  err := true; end;
  126.    if (o and LSR_FERR) <> 0 then begin inc(LFERR_count);  err := true; end;
  127.    if (o and LSR_BREAK)<> 0 then begin inc(LBREAK_count); err := true; end;
  128.  
  129.    if err then
  130.    begin
  131.       o := port[ port_base+RBR ];
  132.       exit;
  133.    end;
  134.  
  135.    if ((o and LSR_DAV) = 0) then
  136.       exit;
  137.  
  138.    c := chr( port[ port_base+RBR ] ); io_delay;
  139.  
  140.    if XOFF_active then           (* XOFF cancelled by any character *)
  141.       cancel_xoff
  142.    else
  143.  
  144.    if c = XOFF_char then         (* process XOFF/XON flow control *)
  145.       XOFF_active := true
  146.    else
  147.  
  148.    if (c = ^K) then              (* process cancel-output command *)
  149.       control_k
  150.    else
  151.  
  152.    if c = carrier_lost then      (* ignore this special character! *)
  153.    begin
  154.       {do nothing}
  155.    end
  156.    else
  157.  
  158.    if rxque.count < sizeof(rxque.data) then
  159.    begin
  160.       inc(rxque.count);
  161.       rxque.data[rxque.next_in] := c;
  162.       if rxque.next_in < sizeof(rxque.data) then
  163.          inc(rxque.next_in)
  164.       else
  165.          rxque.next_in := 1;
  166.    end;
  167. end;
  168.  
  169.  
  170. (* ------------------------------------------------------------ *)
  171. procedure INTR_poll_transmit;
  172.    (* recover from CTS or XOF handshake when needed *)
  173. begin
  174.    {no action if nothing to transmit}
  175.    if (txque.count = 0) or (com_chan = 0) then
  176.       exit;
  177.  
  178.    {check for XON if output suspended by XOFF}
  179.    disable_int;
  180.    INTR_service_receive;
  181.    INTR_service_transmit;
  182.    enable_int;
  183. end;
  184.  
  185.  
  186. (* ------------------------------------------------------------ *)
  187. procedure cancel_xoff;
  188. begin
  189.    XOFF_active := false;
  190.    INTR_poll_transmit;
  191. end;
  192.  
  193.  
  194. (* ------------------------------------------------------------ *)
  195. procedure INTR_check_interrupts;
  196.    (* check for and process any pending 8250 interrupts.
  197.       can be called from TPAS *)
  198. var
  199.    status:  integer;
  200.  
  201. begin
  202.  
  203. (* get the interrupt identification register *)
  204.    status := port[ port_base+IIR ]; io_delay;
  205.  
  206. (* repeatedly service interrupts until no more services possible *)
  207.    while (status and IIR_PENDING) = 0 do
  208.    begin
  209.       {disable_int;}
  210.  
  211.       case (status and IIR_MASK) of
  212.          IIR_MSR:   (* modem status change interrupt *)
  213.             INTR_service_MSR;
  214.  
  215.          IIR_THRE:  (* transmit holding register empty interrupt *)
  216.             INTR_service_transmit;
  217.  
  218.          IIR_DAV:   (* data available interrupt *)
  219.             INTR_service_receive;
  220.  
  221.          IIR_LSR:   (* line status change interrupt *)
  222.             INTR_service_MSR;
  223.       end;
  224.  
  225.       {enable_int;}
  226.  
  227.   (* get the interrupt identification register again *)
  228.       status := port[ port_base+IIR ];
  229.       io_delay;
  230.    end;
  231.  
  232. end;
  233.  
  234.  
  235. (* ------------------------------------------------------------ *)
  236. procedure INTR_interrupt_handler(Flags,CS,IP,AX,BX,CX,DX,SI,DI,DS,ES,BP: word);
  237. interrupt;
  238.    (* low-level interrupt service routine.  this procedure processes
  239.       all receive-ready and transmit-ready interrupts from the 8250 chip.
  240.       DO NOT call this proc from TPAS *)
  241.  
  242. begin
  243.  
  244. (* service interrupts until no more services possible *)
  245.    INTR_check_interrupts;
  246.  
  247. (* acknowledge the interrupt and return to foreground operation *)
  248.    port[ $20 ] := $20;   {non-specific EOI} io_delay;
  249.  
  250. end;
  251.  
  252.  
  253. (* ------------------------------------------------------------ *)
  254. function INTR_receive_ready: boolean;
  255.    (* see if any receive data is ready on the active com port *)
  256. begin
  257.    INTR_poll_transmit;
  258.    INTR_receive_ready := rxque.count > 0;
  259. end;
  260.  
  261.  
  262. (* ------------------------------------------------------------ *)
  263. procedure INTR_flush_com;
  264.    (* wait for all pending transmit data to be sent *)
  265. begin
  266.    enable_int;
  267.    while txque.count > 0 do
  268.    begin
  269.       INTR_poll_transmit;
  270.       give_up_time;             (* give up extra time *)
  271.    end;
  272. end;
  273.  
  274.  
  275. (* ------------------------------------------------------------ *)
  276. procedure verify_txque_space;
  277.    (* wait until there is enough space in the queue for this message *)
  278.    (* or until flow control is released *)
  279. begin
  280.    while txque.count > queue_low_water do
  281.    begin
  282.       INTR_poll_transmit;
  283.       give_up_time;             (* give up extra time *)
  284.    end;
  285. end;
  286.  
  287.  
  288. (* ------------------------------------------------------------ *)
  289. procedure INTR_lower_dtr;
  290.    (* lower DTR to inhibit modem answering *)
  291. var
  292.    o: byte;
  293. begin
  294.    if (com_chan = 0) then exit;
  295.  
  296.    o := port [ port_base+MCR ];                 io_delay;
  297.    port[ port_base+MCR ] := o and not MCR_DTR;  io_delay;
  298. end;
  299.  
  300.  
  301. (* ------------------------------------------------------------ *)
  302. procedure INTR_raise_dtr;
  303.    (* raise DTR to allow modem answering - not supported by BIOS *)
  304. var
  305.    o: byte;
  306. begin
  307.    if com_chan = 0 then exit;
  308.  
  309.    o := port [ port_base+MCR ];                       io_delay;
  310.    port[ port_base+MCR ] := o or (MCR_DTR+MCR_RTS);   io_delay;
  311. end;
  312.  
  313.  
  314. (* ------------------------------------------------------------ *)
  315. procedure INTR_select_port;
  316.    (* lookup the port address for the specified com channel *)
  317. begin
  318.    xmit_active := false;
  319.    XOFF_active := false;
  320.  
  321.    if (com_chan > 0) and (com_chan <= M